package com.example.scanner.zxing.barcode;

import com.google.zxing.*;
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.oned.Code128Writer;
import com.google.zxing.oned.EAN13Writer;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.Map;

/**
 * 条形码生成和识别工具类
 *
 * @author zwg
 * @date 2025/8/12 22:59
 */
public class BarcodeUtil {

    // 条形码格式枚举
    public enum BarcodeFormat {
        CODE_128,
        EAN_13
    }

    /**
     * 生成条形码图片
     * @param content 条形码内容
     * @param format 条形码格式
     * @param width 图片宽度
     * @param height 图片高度
     * @param outputPath 输出文件路径
     * @return 是否生成成功
     */
    public static boolean generateBarcode(String content, BarcodeFormat format,
                                          int width, int height, String outputPath) {
        try {
            // 设置条形码参数
            Map<EncodeHintType, Object> hints = new HashMap<>();
            hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
            hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);

            // 根据选择的格式创建相应的Writer
            com.google.zxing.Writer writer;
            switch (format) {
                case EAN_13:
                    // EAN-13需要13位数字
                    if (content.length() != 13 || !content.matches("\\d+")) {
                        System.out.println("EAN-13条形码必须是13位数字");
                        return false;
                    }
                    writer = new EAN13Writer();
                    break;
                case CODE_128:
                default:
                    writer = new Code128Writer();
                    break;
            }

            // 生成矩阵
            BitMatrix bitMatrix = writer.encode(content,
                    com.google.zxing.BarcodeFormat.valueOf(format.name()), width, height, hints);

            // 输出为图片
            Path path = new File(outputPath).toPath();
            MatrixToImageWriter.writeToPath(bitMatrix, "PNG", path);

            System.out.println("条形码生成成功: " + outputPath);
            return true;

        } catch (Exception e) {
            System.out.println("条形码生成失败: " + e.getMessage());
            return false;
        }
    }

    /**
     * 生成包含文本内容的条形码图片
     * @param content 条形码内容（同时会显示为文本）
     * @param format 条形码格式
     * @param width 图片宽度
     * @param height 图片高度（不包含文本区域）
     * @param outputPath 输出文件路径
     * @return 是否生成成功
     */
    public static boolean generateBarcodeWithText(String content, BarcodeFormat format,
                                                  int width, int height, String outputPath) {
        try {
            // 设置条形码参数
            Map<EncodeHintType, Object> hints = new HashMap<>();
            hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
            hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);

            // 根据选择的格式创建相应的Writer
            com.google.zxing.Writer writer;
            switch (format) {
                case EAN_13:
                    // EAN-13需要13位数字
                    if (content.length() != 13 || !content.matches("\\d+")) {
                        System.out.println("EAN-13条形码必须是13位数字");
                        return false;
                    }
                    writer = new EAN13Writer();
                    break;
                case CODE_128:
                default:
                    writer = new Code128Writer();
                    break;
            }

            // 生成矩阵
            BitMatrix bitMatrix = writer.encode(content,
                    com.google.zxing.BarcodeFormat.valueOf(format.name()), width, height, hints);

            // 将BitMatrix转换为BufferedImage
            BufferedImage barcodeImage = toBufferedImage(bitMatrix);

            // 创建新的图片，预留文本区域（在条形码下方）
            int textHeight = 30; // 文本区域高度
            BufferedImage finalImage = new BufferedImage(width, height + textHeight, BufferedImage.TYPE_INT_RGB);

            // 创建Graphics2D用于绘制
            Graphics2D g2d = finalImage.createGraphics();

            // 设置背景为白色
            g2d.setColor(Color.WHITE);
            g2d.fillRect(0, 0, width, height + textHeight);

            // 绘制条形码
            g2d.drawImage(barcodeImage, 0, 0, null);

            // 绘制文本
            g2d.setColor(Color.BLACK);
            g2d.setFont(new Font("Arial", Font.PLAIN, 16));
            FontMetrics metrics = g2d.getFontMetrics();

            // 计算文本居中位置
            int textX = (width - metrics.stringWidth(content)) / 2;
            int textY = height + (textHeight + metrics.getHeight()) / 2 - metrics.getDescent();

            // 绘制文本
            g2d.drawString(content, textX, textY);

            // 释放资源
            g2d.dispose();

            // 保存最终图片
            ImageIO.write(finalImage, "PNG", new File(outputPath));

            System.out.println("带文本的条形码生成成功: " + outputPath);
            return true;

        } catch (Exception e) {
            System.out.println("条形码生成失败: " + e.getMessage());
            return false;
        }
    }

    /**
     * 将BitMatrix转换为BufferedImage
     */
    private static BufferedImage toBufferedImage(BitMatrix matrix) {
        int width = matrix.getWidth();
        int height = matrix.getHeight();
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);

        for (int x = 0; x < width; x++) {
            for (int y = 0; y < height; y++) {
                image.setRGB(x, y, matrix.get(x, y) ? 0xFF000000 : 0xFFFFFFFF);
            }
        }
        return image;
    }

    /**
     * 识别条形码图片
     * @param imagePath 图片路径
     * @return 识别到的内容
     */
    public static String readBarcode(String imagePath) {
        try {
            // 读取图片文件
            File imageFile = new File(imagePath);
            if (!imageFile.exists()) {
                System.out.println("图片文件不存在");
                return null;
            }

            BufferedImage image = ImageIO.read(imageFile);
            if (image == null) {
                System.out.println("无法读取图片文件");
                return null;
            }

            // 转换为ZXing需要的格式
            LuminanceSource source = new BufferedImageLuminanceSource(image);
            BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));

            // 设置识别参数
            Map<DecodeHintType, Object> hints = new HashMap<>();
            hints.put(DecodeHintType.CHARACTER_SET, "UTF-8");
            // 尝试识别多种条形码格式
            hints.put(DecodeHintType.POSSIBLE_FORMATS,
                    java.util.Arrays.asList(
                            com.google.zxing.BarcodeFormat.CODE_128,
                            com.google.zxing.BarcodeFormat.EAN_13,
                            com.google.zxing.BarcodeFormat.EAN_8,
                            com.google.zxing.BarcodeFormat.UPC_A,
                            com.google.zxing.BarcodeFormat.UPC_E
                    ));

            // 识别条形码
            MultiFormatReader reader = new MultiFormatReader();
            Result result = reader.decode(bitmap, hints);

            System.out.println("识别到的条形码内容: " + result.getText());
            System.out.println("条形码格式: " + result.getBarcodeFormat());

            return result.getText();

        } catch (NotFoundException e) {
            System.out.println("未识别到条形码");
        } catch (IOException e) {
            System.out.println("图片读取错误: " + e.getMessage());
        } catch (Exception e) {
            System.out.println("条形码识别失败: " + e.getMessage());
        }
        return null;
    }
}
